public class Calculation
{
	//left index as 0 so I can refer to months by the actual index
	//march will be monthDays[3] instead of [2]
	private final int[] monthDays = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,};
	
	private double latitude;
	private double longitude;
	double standardMeridian;
	private int year;
	private int month;
	private int day;
	private int dayOfYear;
	private boolean dst;
	
	/**
	 * constructor for calculation class
	 * initializes the variables for everything needed
	 * 
	 * @param lat	latitude of user
	 * @param lon	longitude of user
	 * @param year	year the sundial is to be used
	 * @param month	month the sundial is to be used
	 * @param day	day the sundial is to be used
	 * @param std_mer	standard meridian of where the sundial will be used
	 */
	public Calculation(double lat, double lon, int year, int month, int day, double std_mer, boolean dst)
	{
		latitude = lat;
		longitude = lon;
		standardMeridian = std_mer;
		this.year = year;
		this.month = month;
		this.day = day;
		dayOfYear = findDayOfYear();
		this.dst = dst;
	}
	
	//find the day of the year for the equation of time formula
	private int findDayOfYear()
	{
		int dayNum = 0;
		boolean leap = false;
		//leap year
		if(year % 4 == 0)
		{
			leap = true;
		}
		//sums all the days of the months prior to current month
		for(int i = 1; i < month; i ++)
		{
			dayNum += monthDays[i];
			//if february and leap year add 1 day
			if( i == 2 && leap)
			{
				dayNum++;
			}
		}
		//adds current day to count to get right number
		dayNum += day;
		
		return dayNum;
	}
	
	//just gets the difference between longitude and the standard meridian
	private double findLongitudeShift()
	{
		return longitude - standardMeridian;
	}
	
	//get the equation of time number to subtract from the apparent time
	//used the formula on the site provided
	private double ET()
	{
		double e = 0;
		
		double B = 360 * (dayOfYear-81)/365;
		
		e = 9.87 * Math.sin(2*B) - 7.53 * Math.cos(B) - 1.5 * Math.sin(B);
		
		return e;
	}

	
	/**
	 *hour is the hour from noon
	 *negative is before noon and positive is after noon
	 *-1 would be 11am
	 *3 would be 3pm
	 *-4 would be 8 am
	 *it will return a double which is the degree of the line to be displayed
	 *this degree is the degree representation of the standard time
	 *
	 *the equation is tan(d) = tan(t) * sin(phi)
	 *d is the angle which the hour line makes with the gnomon
	 *t is the time measured from noon in degrees of arc
	 *phi is the latitude of the place the sundial is located
	 */
	public double getHourLine(int hour)
	{
		//get the minutes from noon that will give apparent time
		double minutesFromNoon = hour*60;
		
		//add the time difference to the apparent time caused by
		//longitude difference from standard meridian
		minutesFromNoon += (int)findLongitudeShift();
		
		//subtract equation of time from apparent time to get standard time
		minutesFromNoon -= (int)ET();
		
		//change minutes to degrees of arc to work with the equation
		minutesFromNoon = timeToArc(minutesFromNoon);

		//t from the equation in degrees
		//use this variable to keep things going along with the equation
		double t = minutesFromNoon;
		
		//phi from the equation in degrees
		double phi = latitude;
		
		//change to radians because java needs it as radians to do trig functions
		phi = Math.toRadians(phi);
		t = Math.toRadians(t);
		
		double sinPhi = Math.sin(phi);
		double tanT = Math.tan(t);
		

		//this gives me where the line should be in radians
		double d = Math.atan(tanT * sinPhi);
		
		//change back to degrees
		d = Math.toDegrees(d);

		return d;
	}

	public double getGnomonAngle()
	{
		return latitude;
	}

	//time here is in minutes
	//changes it to degrees of arc
	private double timeToArc(double minutes)
	{
		boolean negative = false;
		double time = minutes;
		if(time < 0)
		{
			negative = true;
			time = Math.abs(time);
		}
		double hour = (int)(time / 60);
		double min = time % 60;
		
		//return a negative value 
		if(negative)
		{
			return 0 - (hourToDeg(hour) + minToDeg(min));
		}
		else
		{
			return hourToDeg(hour) + minToDeg(min);
		}
	}

	private double hourToDeg(double hour)	
	{	
		return (hour * 15);
	}
	
	
	private double minToDeg(double min)
	{
		return (min / 4);
	}
	
	public boolean isDST()
	{
		return dst;
	}
}
